home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
graphic
/
pvquan16.zip
/
QUANT
/
HECKBERT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-30
|
17KB
|
568 lines
/************************************************************************
* *
* Copyright (c) 1991, Frank van der Hulst *
* All Rights Reserved *
* *
* Authors: *
* FvdH - Frank van der Hulst (Wellington, NZ) *
* *
* Versions: *
* V1.1 910626 FvdH - QUANT released for DBW_RENDER *
* V1.2 911021 FvdH - QUANT released for PoV Ray *
* V1.4 920303 FvdH - Ported to GNU *
* V1.6 921023 FvdH - Produce multi-image GIFs *
* - Port to OS/2 IBM C Set/2 *
* *
************************************************************************/
/*
* This software is copyrighted as noted below. It may be freely copied,
* modified, and redistributed, provided that the copyright notice is
* preserved on all copies.
*
* There is no warranty or other guarantee of fitness for this software,
* it is provided solely "as is". Bug reports or fixes may be sent
* to the author, who may or may not act on them as he desires.
*
* You may not include this software in a program or other software product
* without supplying the source, or without informing the end-user that the
* source is available for no extra charge.
*
* If you modify this software, you should include a notice giving the
* name of the person performing the modification, the date of modification,
* and the reason for such modification.
*/
/*
* colorquant.c
*
* Perform variance-based color quantization on a "full color" image.
* Author: Craig Kolb
* Department of Mathematics
* Yale University
* kolb@yale.edu
* Date: Tue Aug 22 1989
* Copyright (C) 1989 Craig E. Kolb
* $Id: colorquant.c,v 1.3 89/12/03 18:27:16 craig Exp $
*
* $Log: colorquant.c,v $
*
* Revision 1.4 91/06/26 16:00:00 Frank van der Hulst
* Ported to Turbo C;
* Call farmalloc rather than malloc
* Virtual memory added to swap box data to/from disk
* Rewritten in ANSI C
* Removed call to QuantHistogram() from colorquant, to allow two
* image files to create one palette
* Changed QuantHistogram() to read from file, rather than from an
* array
* Changed format of palette to conform with the VGA palette
*
* Revision 1.3 89/12/03 18:27:16 craig
* Removed bogus integer casts in distance calculation in makenearest().
*
* Revision 1.2 89/12/03 18:13:12 craig
* FindCutpoint now returns FALSE if the given box cannot be cut. This
* to avoid overflow problems in CutBox.
* "whichbox" in GreatestVariance() is now initialized to 0.
*
*/
#ifdef __TURBOC__
#include <mem.h>
#define HUGE 1.79e308
#endif
#include <math.h>
#include "quant.h"
#include "heckbert.h"
#define MAX(x,y) ((x) > (y) ? (x) : (y))
static unsigned long NPixels = 0L; /* total # of pixels */
static int neighbours[MAXCOLORS];
/*
* Compute the histogram of the image as well as the projected frequency
* arrays for the first world-encompassing box.
* We compute both the histogram and the proj. frequencies of
* the first box at the same time to save a pass through the
* entire image.
* The projected frequency arrays of the largest box are zeroed out as
* as part of open_box_file(), called from main().
*/
void QuantHistogram(Box *box)
{
unsigned long *rf, *gf, *bf;
UCHAR pixel[3];
rf = box->freq[RED];
gf = box->freq[GREEN];
bf = box->freq[BLUE];
while (get_pixel(pixel)) {
rf[pixel[RED]]++;
gf[pixel[GREEN]]++;
bf[pixel[BLUE]]++;
Histogram[(((pixel[RED]<<INPUT_BITS)|pixel[GREEN])<<INPUT_BITS)|pixel[BLUE]]++;
NPixels++;
}
}
/*
* Compute mean and weighted variance of the given box.
*/
void BoxStats(Box HUGE_PTR box)
{
int i, color;
unsigned long *freq;
double mean, var;
if(box->weight == 0) {
box->weightedvar = 0;
return;
}
box->weightedvar = 0.0;
for (color = 0; color < 3; color++) {
var = mean = 0;
i = box->low[color];
freq = &box->freq[color][i];
for (; i < box->high[color]; i++, freq++) {
mean += i * *freq;
var += i*i* *freq;
}
box->mean[color] = mean / box->weight;
box->weightedvar += var - box->mean[color]*box->mean[color]*box->weight;
}
box->weightedvar /= NPixels;
}
/*
* Return the number of the box in 'boxes' with the greatest variance.
* Restrict the search to those boxes with indices between 0 and n-1.
*/
int GreatestVariance(int n)
{
int i, whichbox = 0;
double max;
Box *box;
max = -1;
for (i = 0; i < n; i++) {
box = get_box_tmp(i);
if (box->weightedvar > max) {
max = box->weightedvar;
whichbox = i;
}
}
return whichbox;
}
/*
* Update projected frequency arrays for two boxes which used to be
* a single box.
*/
void UpdateFrequencies(Box HUGE_PTR box1, Box HUGE_PTR box2)
{
unsigned long myfreq, HUGE_PTR h;
int b, g, r;
int roff;
memset(box1->freq[0], 0, IN_COLOURS * sizeof(unsigned long));
memset(box1->freq[1], 0, IN_COLOURS * sizeof(unsigned long));
memset(box1->freq[2], 0, IN_COLOURS * sizeof(unsigned long));
for (r = box1->low[0]; r < box1->high[0]; r++) {
roff = r << INPUT_BITS;
for (g = box1->low[1];g < box1->high[1]; g++) {
b = box1->low[2];
h = Histogram + (((roff | g) << INPUT_BITS) | b);
for (; b < box1->high[2]; b++) {
if ((myfreq = *h++) == 0)
continue;
box1->freq[0][r] += myfreq;
box1->freq[1][g] += myfreq;
box1->freq[2][b] += myfreq;
box2->freq[0][r] -= myfreq;
box2->freq[1][g] -= myfreq;
box2->freq[2][b] -= myfreq;
}
}
}
}
/*
* Compute the 'optimal' cutpoint for the given box along the axis
* indicated by 'color'. Store the boxes which result from the cut
* in newbox1 and newbox2.
*/
int FindCutpoint(Box HUGE_PTR box, int color, Box HUGE_PTR newbox1, Box HUGE_PTR newbox2)
{
double u, v, max;
int i, maxindex, minindex, cutpoint;
unsigned long optweight, curweight;
if (box->low[color] + 1 == box->high[color])
return FALSE; /* Cannot be cut. */
minindex = (int)((box->low[color] + box->mean[color]) * 0.5);
maxindex = (int)((box->mean[color] + box->high[color]) * 0.5);
cutpoint = minindex;
optweight = box->weight;
curweight = 0.;
for (i = box->low[color] ; i < minindex ; i++)
curweight += box->freq[color][i];
u = 0.;
max = -1;
for (i = minindex; i <= maxindex ; i++) {
curweight += box->freq[color][i];
if (curweight == box->weight)
break;
u += (double)(i * box->freq[color][i]) / box->weight;
v = ((double)curweight / (box->weight-curweight)) *
(box->mean[color]-u)*(box->mean[color]-u);
if (v > max) {
max = v;
cutpoint = i;
optweight = curweight;
}
}
cutpoint++;
*newbox1 = *newbox2 = *box;
newbox1->weight = optweight;
newbox2->weight -= optweight;
newbox1->high[color] = cutpoint;
newbox2->low[color] = cutpoint;
UpdateFrequencies(newbox1, newbox2);
BoxStats(newbox1);
BoxStats(newbox2);
return TRUE; /* Found cutpoint. */
}
/*
* Cut the given box. Returns TRUE if the box could be cut, FALSE otherwise.
*/
int CutBox(Box HUGE_PTR box, Box HUGE_PTR newbox)
{
int i;
double totalvar[3];
static Box newboxes[3][2]; /* Only used by CutBox, but don't want it on stack */
if (box->weightedvar == 0. || box->weight == 0)
/*
* Can't cut this box.
*/
return FALSE;
/*
* Find 'optimal' cutpoint along each of the red, green and blue
* axes. Sum the variances of the two boxes which would result
* by making each cut and store the resultant boxes for
* (pos